package com.sanji.audio_test

import android.app.Notification
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Intent
import android.os.Build
import android.os.Handler
import android.os.Looper
import android.telecom.Call
import android.telecom.InCallService
import android.util.Log

/**
 * 通话服务类，用于在通话过程中播放音频文件
 * 继承自 [InCallService]，实现 [PlayerThread.OnPlaybackCompletedListener] 接口
 */
class PlayerInCallService : InCallService(), PlayerThread.OnPlaybackCompletedListener {
    companion object {
        private val TAG = PlayerInCallService::class.java.simpleName
        // TODO 暂时的通知ID
        private const val NOTIFICATION_ID_START = 1
        private const val NOTIFICATION_ID_END = 2
        private const val NOTIFICATION_ID_FAILED = 3
    }

    private lateinit var prefs: Preferences
    private lateinit var notificationHelper: NotificationHelper
    private val handler = Handler(Looper.getMainLooper())

    /**
     * 每个活动通话的播放器线程。当通话断开连接时，它会立即从该映射中移除，
     * 并且 [pendingExit] 会增加。
     */
    private val players = HashMap<Call, PlayerThread>()

    /**
     * 通话断开连接后等待退出的线程数。如果播放器线程在通话断开之前失败，
     * 这个值可能是负数。
     */
    private var pendingExit = 0

    private var failedNotificationId = NOTIFICATION_ID_FAILED

    /**
     * 通话状态变化回调
     * 监听通话状态变化并相应地处理播放逻辑
     */
    private val callback = object : Call.Callback() {
        override fun onStateChanged(call: Call, state: Int) {
            super.onStateChanged(call, state)
            Log.d(TAG, "onStateChanged: $call, $state")

            handleStateChange(call)
        }
    }

    /**
     * 服务创建时初始化偏好设置和通知助手
     */
    override fun onCreate() {
        super.onCreate()

        prefs = Preferences(this)
        notificationHelper = NotificationHelper(this)
    }

    /**
     * 当有新通话加入时调用
     * 注册通话状态回调并处理初始状态
     * @param call 新加入的通话
     */
    override fun onCallAdded(call: Call) {
        super.onCallAdded(call)
        Log.d(TAG, "onCallAdded: $call")

        call.registerCallback(callback)
        handleStateChange(call)
    }

    /**
     * 当通话被移除时调用
     * 注销通话状态回调并处理状态变化
     * @param call 被移除的通话
     */
    override fun onCallRemoved(call: Call) {
        super.onCallRemoved(call)
        Log.d(TAG, "onCallRemoved: $call")

        call.unregisterCallback(callback)
        handleStateChange(call)
    }

    /**
     * 当通话变为活动状态时启动新的播放器线程，当通话断开时取消它。
     *
     * 当通话断开时，通话会从 [players] 中移除，[pendingExit] 会增加。
     * 当线程实际完成时，[pendingExit] 会减少，如果发生错误，这可能在通话断开之前。
     * @param call 状态发生变化的通话
     */
    private fun handleStateChange(call: Call) {
        val state = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            call.details.state
        } else {
            @Suppress("DEPRECATION")
            call.state
        }

        if (state == Call.STATE_ACTIVE) {
            if (!prefs.isEnabled) {
                Log.v(TAG, "通话音频播放已禁用")
            } else if (!players.containsKey(call)) {
                // 播放开始时发送通知
                notificationHelper.showNotification(
                    "录音播放开始",
                    "正在播放录音文件...",
                    NOTIFICATION_ID_START
                )

                val player = PlayerThread(this, this, call)
                players[call] = player

                updateForegroundState()
                player.start()
            }
        } else if (state == Call.STATE_DISCONNECTING || state == Call.STATE_DISCONNECTED) {
            val player = players[call]
            if (player != null) {
                player.cancel()

                players.remove(call)

                // 在线程退出之前不要更改前台状态
                ++pendingExit
            }
        }
    }

    /**
     * 当没有活动通话且所有播放器线程都已退出时，停止前台服务并移除通知。
     */
    private fun updateForegroundState() {
        // 如果还有活动播放器或正在等待退出的线程，则不退出前台状态
        if (players.isNotEmpty() || pendingExit != 0) {
            return
        }
        
        stopForeground(STOP_FOREGROUND_REMOVE)
    }
    
    /**
     * 当播放器线程退出时调用
     * 减少待退出线程计数并更新前台状态
     */
    private fun onThreadExited() {
        --pendingExit
        updateForegroundState()
    }

    /**
     * 当播放完成时调用
     * 发送播放完成通知并处理线程退出逻辑
     * @param thread 完成播放的线程
     */
    override fun onPlaybackCompleted(thread: PlayerThread) {
        Log.i(TAG, "播放完成: ${thread.id}")
        handler.post {
            // 播放完成时发送通知
            notificationHelper.showNotification(
                "录音播放结束",
                "录音文件播放已完成",
                NOTIFICATION_ID_END
            )
            onThreadExited()
        }
    }

    /**
     * 当播放失败时调用
     * 发送播放失败通知并处理线程退出逻辑
     * @param thread 播放失败的线程
     * @param errorMsg 错误信息
     */
    override fun onPlaybackFailed(thread: PlayerThread, errorMsg: String?) {
        Log.w(TAG, "播放失败: ${thread.id}: $errorMsg")
        handler.post {
            onThreadExited()

            // 播放失败时发送通知
            notificationHelper.showNotification(
                "录音播放失败",
                errorMsg ?: "未知错误",
                failedNotificationId
            )
            ++failedNotificationId
        }
    }
}